package org.jeecg.modules.service.impl;

import cn.hutool.core.date.BetweenFormater;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.entity.RunnerMatch;
import org.jeecg.modules.entity.RunnerMatchDevice;
import org.jeecg.modules.entity.RunnerMatchPlayer;
import org.jeecg.modules.entity.RunnerMatchScore;
import org.jeecg.modules.model.MatchData;
import org.jeecg.modules.service.*;
import org.jeecg.modules.socket.MatchTimeSocketServer;
import org.jeecg.modules.socket.MqttSocketServer;
import org.jeecg.modules.utill.MqttUtil;
import org.parboiled.matchers.MatcherUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author tanxy
 * @date 2022年12月01日 17:25
 */
@Service
@Slf4j
public class MatchServiceImpl implements MatchService {
    @Autowired
    private MqttSocketServer mqttSocketServer;
    @Autowired
    private IRunnerMatchPlayerService runnerMatchPlayerService;
    @Autowired
    private IRunnerMatchScoreService matchScoreService;
    @Autowired
    private IRunnerMatchDeviceService deviceService;
    @Autowired
    private IRunnerMatchService matchService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MatchTimeSocketServer matchTimeSocketServer;

    @Override
    public void calling(String uid) {
        /**
         * 根据uid获取到当前在进行的比赛中所属的比赛
         * @author tanxy
         * @date 2023/2/26 16:53
         * @param uid
         */

        QueryWrapper<RunnerMatchPlayer> wrapperRing = new QueryWrapper<>();
        wrapperRing.eq("ringcode", uid);
        List<RunnerMatchPlayer> list = runnerMatchPlayerService.list(wrapperRing);
        //在保障一个芯片只有一个用户时，即可完成直接进行确认比赛ID和websocket人ID
        if (!list.isEmpty()) {
            String matchId = list.get(0).getMatchid();
            Map<String, String> matchMap = MqttUtil.MATCH_MAP;
            Set<String> userIds = matchMap.keySet();
            String userId = "";
            for (String userIdT : userIds) {
                String matchIdT = matchMap.get(userIdT);
                if (matchIdT.equals(matchId)) {
                    userId = userIdT;
                    break;
                }
            }
            if (StrUtil.isNotEmpty(matchId)) {
                List<RunnerMatchPlayer> runnerMatchPlayers = runnerMatchPlayerService.selectByMainId(matchId);
                boolean isHas = false;
                for (RunnerMatchPlayer player : runnerMatchPlayers) {
                    if (uid.equals(player.getRingcode())) {
                        isHas = true;
                        //mqttSocketServer.sendAllMessage(JSON.toJSONString(Result.ok(player)));
                        mqttSocketServer.sendOneMessage(userId, JSON.toJSONString(Result.ok(player)));
                    }
                }
                if (!isHas) {
                    mqttSocketServer.sendOneMessage(userId, JSON.toJSONString(Result.error("无此用户信息")));
                }
            } else {
                mqttSocketServer.sendOneMessage(userId, JSON.toJSONString(Result.error("无开始比赛")));
            }
        } else {
            log.error("该芯片没有绑定人员,UID: " + uid);
        }
    }

    @Override
    public void match(MatchData matchData) throws Exception {

        QueryWrapper<RunnerMatchPlayer> wrapperRing = new QueryWrapper<>();
        wrapperRing.eq("ringcode", matchData.getUid());
        List<RunnerMatchPlayer> playerList = runnerMatchPlayerService.list(wrapperRing);

        String userId = "";
        if (!playerList.isEmpty()) {
            String matchId = playerList.get(0).getMatchid();
            Map<String, String> matchMap = MqttUtil.MATCH_MAP;
            Set<String> userIds = matchMap.keySet();
            for (String userIdT : userIds) {
                String matchIdT = matchMap.get(userIdT);
                if (matchIdT.equals(matchId)) {
                    userId = userIdT;
                    break;
                }
            }
        }

        String matchId = MqttUtil.MATCH_MAP.get(userId);

        List<String> groupIds = MqttUtil.MATCH_GROUPID_MAP.get(userId);
        int timeInterval = MqttUtil.TIME_INTERVAL * 1000;
        String uid = matchData.getUid();
        if (StrUtil.isNotEmpty(matchId) && !groupIds.isEmpty()) {
            List<RunnerMatchPlayer> runnerMatchPlayers = runnerMatchPlayerService.selectByMainIdAndGroupId(matchId, groupIds);
            boolean isHas = false;
            for (RunnerMatchPlayer player : runnerMatchPlayers) {
                if (uid.equals(player.getRingcode())) {
                    isHas = true;
                    /***
                     *1. 如果结束时间是空，说明还没有比赛开始
                     * 2. 不是空 则结束时间+timeInterval < matchData.getTime()
                     * ------
                     * 1. 最新逻辑 开始记录已经有了开始时间了
                     * 2. 有设备来了，就应该是起点、中点、终点
                     */
                    String runnerType = MqttUtil.RUNNER_TYPE_MAP.get(userId);
                    if (StrUtil.isNotEmpty(runnerType)) {
                        //part 段比赛   round圈比赛  AB  a点到b点比赛
                        if ("AB".equals(runnerType)) {
                            //比赛类型
                            recordABScore(player, matchData, userId);
                        } else if ("part".equals(runnerType)) {
                            //A 点既是起点也是终点（起终点）
                            recordPartScore(player, matchData, userId);
                        } else {
                            //round 绕圈（起点终点不在一起）
                            recodRoundScore(player, matchData, userId);
                        }
                    } else {
                        //默认段比赛
                        recordPartScore(player, matchData, userId);
                    }
                    break;
                }
            }
            if (!isHas) {
                log.error("监测不到改运动员信息，芯片号为:" + uid);
            }
        } else {
            log.error("没有比赛在进行...");
        }
    }

    @Override
    public void match(List<MatchData> matchDatas) throws Exception {
        for (MatchData matchData : matchDatas) {
            match(matchData);
        }
    }

    //现在都有开始时间了，所以已经没有首次进来只说,同时也不需要更新结束时间了 ，结束时间以设备的结束时间为准
    //现在只需要记录结束时间即可
    private void updateScore(RunnerMatchPlayer player, MatchData matchData, String userId) {

        String matchId = MqttUtil.MATCH_MAP.get(userId);

        List<RunnerMatchDevice> runnerMatchDevices = deviceService.selectByMainIdAndFlag(matchId, "0");
        String timePoint = "";
        for (RunnerMatchDevice device : runnerMatchDevices) {
            timePoint = device.getTimePoint();
            break;
        }
        QueryWrapper<RunnerMatchScore> wrapper = new QueryWrapper<>();
        wrapper.eq("matchid", matchId).eq("player", player.getPlayer())
                .eq("groupid", player.getGroupid());
        if (StrUtil.isNotEmpty(timePoint)) {
            //有起点
            wrapper.eq("time_point", timePoint);
        }

        RunnerMatchScore one = matchScoreService.getOne(wrapper, false);
        if (null != one) {
            long time = matchData.getTime();
            Calendar instance = Calendar.getInstance();
            instance.setTimeInMillis(time);
            Date endTime = instance.getTime();

            try {
                if (StrUtil.isEmpty(timePoint)) {
                    //没有起点设备，只需要结束时间即可
                    //更新结束时间
                    player.setPendtime(endTime);
                    //更新总成绩
                    String zcj = formatBetween(player.getPstarttime(), endTime);
                    player.setScore(zcj);
                } else {
                    //说明该选手在起点是有成绩的
                    //获取起点成绩
                    String reachTime = one.getReachTime();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss-SS");
                    Date qd = sdf.parse(reachTime);
                    //更新结束时间
                    player.setPendtime(endTime);

                    //更新净成绩
                    String jcj = formatBetween(qd, endTime);
                    player.setScorecj(jcj);

                }
                runnerMatchPlayerService.updateById(player);
            } catch (ParseException e) {
                log.error(e.getMessage());
                log.error("该选手在节点上没有成绩，计算总成绩报错...");
            }

        }

    }

    //记录圈比赛
    private void recodRoundScore(RunnerMatchPlayer player, MatchData matchData, String userId) throws Exception{

        String matchId = MqttUtil.MATCH_MAP.get(userId);

        long time = matchData.getTime();
        Calendar instance = Calendar.getInstance();
        instance.setTimeInMillis(time);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss-SS");
        Date recordTime = instance.getTime();
        String format = sdf.format(recordTime);

        String betweenTime = "";

        QueryWrapper<RunnerMatchScore> wrapper = new QueryWrapper<>();
        wrapper.eq("matchid", matchId).eq("player", player.getPlayer())
                .eq("groupid", player.getGroupid());
        //根据比赛ID和设备ID 获取到比赛中的设备信息
        List<RunnerMatchDevice> matchDevices = deviceService.selectByMainIdAndDevice(matchId,
                matchData.getDeviceId());
        RunnerMatchDevice device = null;
        //获取到传过来的设备信息
        for (RunnerMatchDevice temp : matchDevices) {
            if (matchData.getDeviceId().equals(temp.getDevice())) {
                device = temp;
                break;
            }
        }
        if (device == null) {
            log.error("设备编号不在此次比赛中。。。");
        } else {
            String playerName = player.getPlayer();
            wrapper.eq("matchid", matchId).eq("player", playerName)
                    .eq("groupid", player.getGroupid()).eq("time_point", device.getTimePoint());
            //根据比赛ID  选手信息  组别  计时点 获取一下是否有成绩存在
            RunnerMatchScore one = matchScoreService.getOne(wrapper, false);
            if (null == one) {
                String deviceflag = device.getDeviceflag();
                if (StrUtil.isNotEmpty(deviceflag)) {
                    //计时点成绩是段成绩
                    String playeKey = "Score_" + matchId + playerName;
                    Object upDate = redisUtil.get(playeKey);
                    if (upDate == null) {
                        Date pstarttime = player.getPstarttime();
                        Calendar instanceTemp = Calendar.getInstance();
                        instanceTemp.setTime(pstarttime);
                        long timeInMillis = instanceTemp.getTimeInMillis();
                        redisUtil.set(playeKey, timeInMillis, 60 * 60 * 24);
                        betweenTime = formatBetween(pstarttime, recordTime);
                    } else {
                        Calendar instanceTemp = Calendar.getInstance();
                        instanceTemp.setTimeInMillis((long) upDate);
                        betweenTime = formatBetween(instanceTemp.getTime(), recordTime);
                    }

                    RunnerMatchScore matchScore = new RunnerMatchScore();
                    matchScore.setMatchid(matchId);
                    matchScore.setGroupid(player.getGroupid());
                    matchScore.setPlayer(player.getPlayer());
                    matchScore.setRingcode(player.getRingcode());
                    matchScore.setReachTime(format);
                    matchScore.setCleantime(betweenTime);
                    matchScore.setTimePoint(device.getTimePoint());
                    matchScoreService.saveOrUpdate(matchScore);
                    redisUtil.set(playeKey, matchData.getTime(), 60 * 60 * 24);
                    if ("3".equals(deviceflag)) {
                        //过一次终点记录一圈
                        Integer totalring = player.getTotalring();
                        if (totalring == null) {
                            totalring = 0;
                        }
                        player.setTotalring(totalring + 1);
                        //记录结束时间
                        player.setPendtime(recordTime);
                        //更新总成绩
                        String zcj = formatBetween(player.getPstarttime(), recordTime);
                        player.setScore(zcj);
                        //更新净成绩
                        List<RunnerMatchDevice> runnerMatchDevices = deviceService.selectByMainIdAndFlag(matchId, "0");
                        String qdPoint = "";
                        for (RunnerMatchDevice tempDevice : runnerMatchDevices) {
                            qdPoint = tempDevice.getTimePoint();
                            break;
                        }

                        QueryWrapper<RunnerMatchScore> qdWrapper = new QueryWrapper<>();
                        qdWrapper.eq("matchid", matchId).eq("player", player.getPlayer())
                                .eq("groupid", player.getGroupid()).eq("time_point", qdPoint);
                        RunnerMatchScore qdScore = matchScoreService.getOne(wrapper, false);
                        Date qdTime = sdf.parse(qdScore.getReachTime());
                        String jcj = formatBetween(qdTime, recordTime);
                        player.setScorecj(jcj);
                        runnerMatchPlayerService.updateById(player);
                        matchTimeSocketServer.sendOneMessage(userId,JSON.toJSONString(Result.ok(player)));
                    }
                }
            }
        }
    }

    /**
     * 比赛采用枪声时，使用设备1 台，起点不摆放设备，设备摆放在比赛终点处，
     * 软件设置通过1 次，间隔时间20 秒以上。
     * 只需要 总成绩输出
     * 总成绩 = 计时时间 - 开始时间
     *
     * @param player
     * @param matchData
     * @param userId
     * @author tanxy
     * @date 2023/3/10 9:17
     */
    //记录AB比赛
    private void recordABScore(RunnerMatchPlayer player, MatchData matchData, String userId) throws Exception {
        String matchId = MqttUtil.MATCH_MAP.get(userId);

        String betweenTime = "";

        //根据比赛ID和设备ID 获取到比赛中的设备信息
        List<RunnerMatchDevice> matchDevices = deviceService.selectByMainIdAndDevice(matchId,
                matchData.getDeviceId());
        RunnerMatchDevice device = null;
        //获取到传过来的设备信息，只有一个设备
        for (RunnerMatchDevice temp : matchDevices) {
            if (matchData.getDeviceId().equals(temp.getDevice())) {
                device = temp;
                break;
            }
        }
        if (device == null) {
            log.error("设备编号不在此次比赛中。。。");
        } else {

            QueryWrapper<RunnerMatchScore> wrapper = new QueryWrapper<>();
            String playerName = player.getPlayer();
            wrapper.eq("matchid", matchId).eq("player", playerName)
                    .eq("groupid", player.getGroupid()).eq("time_point", device.getTimePoint());
            //根据比赛ID  选手信息  组别  计时点 获取一下是否有成绩存在
            RunnerMatchScore one = matchScoreService.getOne(wrapper, false);
            if (null == one) {
                String deviceflag = device.getDeviceflag();
                if (StrUtil.isNotEmpty(deviceflag)) {
                    long time = matchData.getTime();
                    Calendar instance = Calendar.getInstance();
                    instance.setTimeInMillis(time);
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss-SS");
                    Date recordTime = instance.getTime();
                    String format = sdf.format(recordTime);
                    Date pstarttime = player.getPstarttime();
                    betweenTime = formatBetween(pstarttime, recordTime);

                    RunnerMatchScore matchScore = new RunnerMatchScore();
                    matchScore.setMatchid(matchId);
                    matchScore.setGroupid(player.getGroupid());
                    matchScore.setPlayer(player.getPlayer());
                    matchScore.setRingcode(player.getRingcode());
                    matchScore.setReachTime(format);
                    matchScore.setCleantime(betweenTime);
                    matchScore.setTimePoint(device.getTimePoint());
                    matchScoreService.saveOrUpdate(matchScore);
                    if ("3".equals(deviceflag)) {
                        //终点 - 要记录结束时间
                        player.setPendtime(recordTime);
                        player.setScore(betweenTime);
                        runnerMatchPlayerService.updateById(player);
                        matchTimeSocketServer.sendOneMessage(userId,JSON.toJSONString(Result.ok(player)));
                    }
                    mqttSocketServer.sendOneMessage(userId,JSON.toJSONString(Result.ok(player)));
                }
            }
        }
    }

    //记录段比赛
    private void recordPartScore(RunnerMatchPlayer player, MatchData matchData, String userId) throws Exception{

        String matchId = MqttUtil.MATCH_MAP.get(userId);

        long time = matchData.getTime();
        Calendar instance = Calendar.getInstance();
        instance.setTimeInMillis(time);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss-SS");
        Date recordTime = instance.getTime();
        String format = sdf.format(recordTime);

        String betweenTime = "";

        //根据比赛ID和设备ID 获取到比赛中的设备信息
        List<RunnerMatchDevice> matchDevices = deviceService.selectByMainIdAndDevice(matchId,
                matchData.getDeviceId());
        RunnerMatchDevice device = null;
        //获取到传过来的设备信息
        for (RunnerMatchDevice temp : matchDevices) {
            if (matchData.getDeviceId().equals(temp.getDevice())) {
                device = temp;
                break;
            }
        }
        if (device == null) {
            log.error("设备编号不在此次比赛中。。。");
        } else {
            String playerName = player.getPlayer();

            QueryWrapper<RunnerMatchScore> wrapper = new QueryWrapper<>();
            wrapper.eq("matchid", matchId).eq("player", playerName)
                    .eq("groupid", player.getGroupid()).eq("time_point", device.getTimePoint());
            //根据比赛ID  选手信息  组别  计时点 获取一下是否有成绩存在
            List<RunnerMatchScore> list = matchScoreService.list(wrapper);
            RunnerMatch match = matchService.getById(matchId);
            //通过终点次数
            Integer runnernum = match.getRunnernum();
            if (list.size() >= runnernum) {
                //如果成绩记录大于设置的圈数，则成绩不再记录
                return;
            } else
            //起点 终点一体且进行跑圈处理的 一个终点要记录多次，第一次为开始时间 以后都为中间时间
            {
                String deviceflag = device.getDeviceflag();
                if (StrUtil.isNotEmpty(deviceflag)) {
                    //计时点成绩是段成绩
                    String playeKey = "Score_" + matchId + playerName;
                    Object upDate = redisUtil.get(playeKey);
                    if (upDate == null) {
                        Date pstarttime = player.getPstarttime();
                        Calendar instanceTemp = Calendar.getInstance();
                        instanceTemp.setTime(pstarttime);
                        long timeInMillis = instanceTemp.getTimeInMillis();
                        redisUtil.set(playeKey, timeInMillis, 60 * 60 * 24);
                        betweenTime = formatBetween(pstarttime, recordTime);
                    } else {
                        Calendar instanceTemp = Calendar.getInstance();
                        instanceTemp.setTimeInMillis((long) upDate);
                        betweenTime = formatBetween(instanceTemp.getTime(), recordTime);
                    }

                    RunnerMatchScore matchScore = new RunnerMatchScore();
                    matchScore.setMatchid(matchId);
                    matchScore.setGroupid(player.getGroupid());
                    matchScore.setPlayer(player.getPlayer());
                    matchScore.setRingcode(player.getRingcode());
                    matchScore.setReachTime(format);
                    matchScore.setCleantime(betweenTime);
                    matchScore.setTimePoint(device.getTimePoint());
                    matchScoreService.saveOrUpdate(matchScore);
                    redisUtil.set(playeKey, matchData.getTime(), 60 * 60 * 24);

                    Integer totalring = player.getTotalring();
                    //更新圈数
                    if(list.size()==0){
                        if (totalring == null) {
                            totalring = 0;
                        }
                    }else {
                        totalring=totalring+1;
                    }
                    player.setTotalring(totalring);

                    if (list.size() == runnernum - 1) {
                        //之前记录的次数 = 设置次数-1  则为最后一圈，要进行更新成绩
                        Date pstarttime = player.getPstarttime();
                        betweenTime = formatBetween(pstarttime, recordTime);
                        player.setPendtime(recordTime);
                        player.setScore(betweenTime);
                        //还需要记录净成绩 净成绩是第一次路过设备的成绩
                        RunnerMatchScore score = list.stream().min(Comparator.comparing(RunnerMatchScore::getCreateTime)).get();
                        Date parse = sdf.parse(score.getReachTime());
                        String formatBetween = formatBetween(parse, recordTime);
                        player.setScorecj(formatBetween);
                        runnerMatchPlayerService.updateById(player);
                        matchTimeSocketServer.sendOneMessage(userId,JSON.toJSONString(Result.ok(player)));
                    }
                }
            }
        }
    }

    //计算两个时间的相差 hh:MM:ss
    private String formatBetween(Date d1, Date d2) {
        String between = DateUtil.formatBetween(d1, d2, BetweenFormater.Level.SECOND);
        String h = "00", m = "00", s = "00";
        if (between.indexOf("小时") != -1) {
            h = between.substring(0, between.indexOf("小时"));
            if (h.length() < 2) {
                h = "0" + h;
            }
        }
        if (between.indexOf("分") != -1) {
            if (h.equals("00")) {
                m = between.substring(0, between.indexOf("分"));
            } else {
                m = between.substring(between.indexOf("小时") + 2, between.indexOf("分"));
            }
            if (m.length() < 2) {
                m = "0" + m;
            }
        }
        if (between.indexOf("秒") != -1) {
            //一场比赛不可能小于一分钟
            s = between.substring(between.indexOf("分") + 1, between.indexOf("秒"));
            if (s.length() < 2) {
                s = "0" + s;
            }
        }
        System.out.println(between);
        System.out.println(h + ":" + m + ":" + s);
        return h + ":" + m + ":" + s;
    }
}
